﻿namespace TNet
{
    using System;
    using System.IO;

    public class Channel
    {
        public bool closed;
        public List<CreatedObject> created = new List<CreatedObject>();
        public string data = string.Empty;
        public List<uint> destroyed = new List<uint>();
        public TcpPlayer host;
        public int id;
        public string level = string.Empty;
        public uint objectCounter = 0xffffff;
        public string password = string.Empty;
        public bool persistent;
        public ushort playerLimit = 0xffff;
        public List<TcpPlayer> players = new List<TcpPlayer>();
        public List<RFC> rfcs = new List<RFC>();

        public void CreateRFC(uint inID, string funcName, TNet.Buffer buffer)
        {
            if (!this.closed && (buffer != null))
            {
                buffer.MarkAsUsed();
                for (int i = 0; i < this.rfcs.size; i++)
                {
                    RFC rfc = this.rfcs[i];
                    if ((rfc.uid == inID) && (rfc.functionName == funcName))
                    {
                        if (rfc.buffer != null)
                        {
                            rfc.buffer.Recycle();
                        }
                        rfc.buffer = buffer;
                        return;
                    }
                }
                RFC item = new RFC {
                    uid = inID,
                    buffer = buffer,
                    functionName = funcName
                };
                this.rfcs.Add(item);
            }
        }

        public void DeleteRFC(uint inID, string funcName)
        {
            for (int i = 0; i < this.rfcs.size; i++)
            {
                RFC rfc = this.rfcs[i];
                if ((rfc.uid == inID) && (rfc.functionName == funcName))
                {
                    this.rfcs.RemoveAt(i);
                    rfc.buffer.Recycle();
                }
            }
        }

        public bool DestroyObject(uint uniqueID)
        {
            if (this.destroyed.Contains(uniqueID))
            {
                return false;
            }
            for (int i = 0; i < this.created.size; i++)
            {
                CreatedObject obj2 = this.created[i];
                if (obj2.uniqueID == uniqueID)
                {
                    if (obj2.buffer != null)
                    {
                        obj2.buffer.Recycle();
                    }
                    this.created.RemoveAt(i);
                    this.DestroyObjectRFCs(uniqueID);
                    return true;
                }
            }
            this.destroyed.Add(uniqueID);
            this.DestroyObjectRFCs(uniqueID);
            return true;
        }

        public void DestroyObjectRFCs(uint objectID)
        {
            int index = 0;
            while (index < this.rfcs.size)
            {
                RFC rfc = this.rfcs[index];
                if (rfc.objectID == objectID)
                {
                    this.rfcs.RemoveAt(index);
                    rfc.buffer.Recycle();
                }
                else
                {
                    index++;
                }
            }
        }

        public bool LoadFrom(BinaryReader reader)
        {
            if (reader.ReadInt32() != 12)
            {
                return false;
            }
            for (int i = 0; i < this.rfcs.size; i++)
            {
                RFC rfc = this.rfcs[i];
                if (rfc.buffer != null)
                {
                    rfc.buffer.Recycle();
                }
            }
            this.rfcs.Clear();
            this.created.Clear();
            this.destroyed.Clear();
            this.level = reader.ReadString();
            this.data = reader.ReadString();
            this.objectCounter = reader.ReadUInt32();
            this.password = reader.ReadString();
            this.persistent = reader.ReadBoolean();
            this.playerLimit = reader.ReadUInt16();
            int num3 = reader.ReadInt32();
            for (int j = 0; j < num3; j++)
            {
                RFC item = new RFC {
                    uid = reader.ReadUInt32()
                };
                if (item.functionID == 0)
                {
                    item.functionName = reader.ReadString();
                }
                TNet.Buffer buffer = TNet.Buffer.Create();
                buffer.BeginWriting(false).Write(reader.ReadBytes(reader.ReadInt32()));
                item.buffer = buffer;
                this.rfcs.Add(item);
            }
            num3 = reader.ReadInt32();
            for (int k = 0; k < num3; k++)
            {
                CreatedObject obj2 = new CreatedObject {
                    playerID = reader.ReadInt32(),
                    uniqueID = reader.ReadUInt32(),
                    objectID = reader.ReadUInt16(),
                    type = 1
                };
                TNet.Buffer buffer2 = TNet.Buffer.Create();
                buffer2.BeginWriting(false).Write(reader.ReadBytes(reader.ReadInt32()));
                buffer2.BeginReading();
                obj2.buffer = buffer2;
                this.created.Add(obj2);
            }
            num3 = reader.ReadInt32();
            for (int m = 0; m < num3; m++)
            {
                this.destroyed.Add(reader.ReadUInt32());
            }
            return true;
        }

        public void RemovePlayer(TcpPlayer p, List<uint> destroyedObjects)
        {
            destroyedObjects.Clear();
            if (this.players.Remove(p))
            {
                if (p == this.host)
                {
                    this.host = null;
                }
                int size = this.created.size;
                while (size > 0)
                {
                    CreatedObject obj2 = this.created[--size];
                    if (obj2.playerID == p.id)
                    {
                        if (obj2.type == 2)
                        {
                            if (obj2.buffer != null)
                            {
                                obj2.buffer.Recycle();
                            }
                            this.created.RemoveAt(size);
                            destroyedObjects.Add(obj2.uniqueID);
                            this.DestroyObjectRFCs(obj2.uniqueID);
                        }
                        else if (this.players.size != 0)
                        {
                            obj2.playerID = this.players[0].id;
                        }
                    }
                }
                if ((!this.persistent || (this.playerLimit < 1)) && (this.players.size == 0))
                {
                    this.closed = true;
                    for (int i = 0; i < this.rfcs.size; i++)
                    {
                        RFC rfc = this.rfcs[i];
                        if (rfc.buffer != null)
                        {
                            rfc.buffer.Recycle();
                        }
                    }
                    this.rfcs.Clear();
                }
            }
        }

        public void Reset()
        {
            for (int i = 0; i < this.rfcs.size; i++)
            {
                this.rfcs[i].buffer.Recycle();
            }
            for (int j = 0; j < this.created.size; j++)
            {
                this.created[j].buffer.Recycle();
            }
            this.rfcs.Clear();
            this.created.Clear();
            this.destroyed.Clear();
            this.objectCounter = 0xffffff;
        }

        public void SaveTo(BinaryWriter writer)
        {
            writer.Write(12);
            writer.Write(this.level);
            writer.Write(this.data);
            writer.Write(this.objectCounter);
            writer.Write(this.password);
            writer.Write(this.persistent);
            writer.Write(this.playerLimit);
            List<uint> list = new List<uint>();
            List<CreatedObject> list2 = new List<CreatedObject>();
            List<RFC> list3 = new List<RFC>();
            for (int i = 0; i < this.created.size; i++)
            {
                CreatedObject item = this.created[i];
                if (item.type == 1)
                {
                    list2.Add(item);
                }
                else
                {
                    list.Add(item.uniqueID);
                }
            }
            for (int j = 0; j < this.rfcs.size; j++)
            {
                RFC rfc = this.rfcs[j];
                if (!list.Contains(rfc.objectID))
                {
                    list3.Add(rfc);
                }
            }
            writer.Write(list3.size);
            for (int k = 0; k < list3.size; k++)
            {
                RFC rfc2 = list3[k];
                writer.Write(rfc2.uid);
                if (rfc2.functionID == 0)
                {
                    writer.Write(rfc2.functionName);
                }
                writer.Write(rfc2.buffer.size);
                if (rfc2.buffer.size > 0)
                {
                    rfc2.buffer.BeginReading();
                    writer.Write(rfc2.buffer.buffer, rfc2.buffer.position, rfc2.buffer.size);
                }
            }
            writer.Write(list2.size);
            for (int m = 0; m < list2.size; m++)
            {
                CreatedObject obj3 = list2[m];
                writer.Write(obj3.playerID);
                writer.Write(obj3.uniqueID);
                writer.Write(obj3.objectID);
                writer.Write(obj3.buffer.size);
                if (obj3.buffer.size > 0)
                {
                    obj3.buffer.BeginReading();
                    writer.Write(obj3.buffer.buffer, obj3.buffer.position, obj3.buffer.size);
                }
            }
            writer.Write(this.destroyed.size);
            for (int n = 0; n < this.destroyed.size; n++)
            {
                writer.Write(this.destroyed[n]);
            }
        }

        public bool hasData
        {
            get
            {
                return (((this.rfcs.size > 0) || (this.created.size > 0)) || (this.destroyed.size > 0));
            }
        }

        public bool isOpen
        {
            get
            {
                return (!this.closed && (this.players.size < this.playerLimit));
            }
        }

        public class CreatedObject
        {
            public TNet.Buffer buffer;
            public ushort objectID;
            public int playerID;
            public byte type;
            public uint uniqueID;
        }

        public class RFC
        {
            public TNet.Buffer buffer;
            public string functionName;
            public uint uid;

            public uint functionID
            {
                get
                {
                    return (this.uid & 0xff);
                }
            }

            public uint objectID
            {
                get
                {
                    return (this.uid >> 8);
                }
            }
        }
    }
}

